#include <stdint.h>
#include <stdio.h>
#include <limits.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <string.h>
#include <pthread.h>
#include <math.h>
#include "global.h"
#include "ietPt100Lib.h"
#include "prt_log.h"

#define LIB_VERSION(a,b,c)                  ((a << 24) + (b << 16) + (c))

#define PT100_MAX_CHANNEL       32          /* PT100 最大通道数 */
#if (HARD_VER == 0)
#define PT100_PT100M_CHANNEL    8           /* PT100 在 PT100 模块中通道数 */
#elif (HARD_VER == 1)
#define PT100_PT100M_CHANNEL    12          /* PT100 在 PT100 模块中通道数 */
#endif

#define PT100_DRV_NAME          "pcie_pt"   /* PT100 驱动名称 */
#define PT100_MAX_SAMP_RATE     100000      /* PT100 最大采样率, Hz */
#define PT100_MAX_SLIDE_WIN     32          /* PT100 滑动平均窗口最大值 */
#define PT100_DEF_SAMP_RATE     50000       /* PT100 默认采样率, 50KHz */
#define PT100_DEF_SLIDE_WIN     4           /* PT100 默认滑动平均窗口, 4 */

#define PT100_RANGE_10V_LSB     305         /* 305uV */
#define PT100_RANGE_2V5_LSB     76          /* 76uV */
#define PT100_RANGE_5V_LSB      152         /* 152uV */

#define PT100_UV_TO_V           1000000     /* PT100 uV -> V */
#define PT100_UV_TO_MV          1000        /* PT100 uV -> mV */
#define PT100_V_2_OHM           100         /* PT100 V -> Ω */

/* IOCTL 命令定义 */
#define IOCTL_PT100_MAGIC                   'P'                                         /* 标识设备驱动 */
#define IOCTL_PT100_SET_MODE                _IOW(IOCTL_PT100_MAGIC, 1, uint8_t)         /* 配置 PT100 模式 */
#define IOCTL_PT100_SET_OSR                 _IOW(IOCTL_PT100_MAGIC, 2, uint8_t)         /* 配置 PT100 过采样 */
#define IOCTL_PT100_SET_SAMP_RATE           _IOW(IOCTL_PT100_MAGIC, 3, uint32_t)        /* 配置 PT100 采样频率 */
#define IOCTL_PT100_SET_IRQ_RATE            _IOW(IOCTL_PT100_MAGIC, 4, uint16_t)        /* 配置 PT100 中断频率 */
#define IOCTL_PT100_SET_SLID_WIN            _IOW(IOCTL_PT100_MAGIC, 5, uint16_t)        /* 配置 PT100 滑动平均窗口 */
#define IOCTL_PT100_SET_RANGE               _IOW(IOCTL_PT100_MAGIC, 6, uint8_t)         /* 配置 PT100 量程 */
#define IOCTL_PT100_GET_VAL                 _IOR(IOCTL_PT100_MAGIC, 7, int32_t)         /* 获取 PT100 数值 */
#define IOCTL_PT100_WAIT_TIM_IRQ            _IOR(IOCTL_AI_MAGIC, 8, int32_t *)          /* 等待 AI 定时中断 */
#define IOCTL_PT100_START                   _IO(IOCTL_PT100_MAGIC,  9)                  /* 开始 PT100 采集 */
#define IOCTL_PT100_STOP                    _IO(IOCTL_PT100_MAGIC,  10)                 /* 停止 PT100 采集 */

#define IOCTL_PT100_GET_DRV_VERSION         _IOR(IOCTL_PT100_MAGIC, 101, uint32_t)      /* 获取驱动版本号 */
#define IOCTL_PT100_GET_FPGA_VERSION        _IOR(IOCTL_PT100_MAGIC, 102, uint32_t)      /* 获取 FPGA 版本号 */

/* 应用层 */

/* 驱动层*/
enum Pt100DevMode {
    PT100_DEV_MOD_NORMAL        = 0,            /* 普通模式 */
    PT100_DEV_MOD_IRQ           = 1,            /* 中断模式 */
    PT100_DEV_MOD_DMA           = 2,            /* DMA 模式 */
};
enum Pt100DevRange {
    PT100_DEV_RANGE_10V         = 0,            /* ±10V */
    PT100_DEV_RANGE_2V5         = 1,            /* ±2.5V */
    PT100_DEV_RANGE_5V          = 2,            /* ±5V */
};

struct Pt100Dev_t {
    void *parent;                                           /* 父指针 */
    char name[32];                                          /* 设备名 */
    uint8_t index;                                          /* 设备号 */

    uint8_t range;                                          /* 量程 */
    int32_t rawVal;                                         /* 原始值 */
    double voltVal;                                         /* 电压数值 */
    double ohmVal;                                          /* 电阻数值 */
    double tempVal;                                         /* 温度数值 */

    int fd;                                                 /* 文件 */
    char path[PATH_MAX];                                    /* 路径 */
};
struct Pt100Ctrl_t {
    char name[16];                                          /* 控制器名 */
    uint8_t num;                                            /* 设备数量 */
    uint8_t max_num;                                        /* 最大数量 */
    struct Pt100Dev_t dev[PT100_MAX_CHANNEL];               /* 设备描述 */
    uint32_t drvVer;                                        /* 驱动 版本号 */
    uint32_t fpgaVer;                                       /* FPGA 版本号 */
    uint32_t libVer;                                        /* 动态库 版本号 */

    uint8_t type;                                           /* 模块类型 */
    uint8_t mode;                                           /* 模式 */
    uint32_t sampRate;                                      /* 采样频率 */
    uint16_t slidWin;                                       /* 滑动平均窗口 */
};
/* PT100 控制器 */
static struct Pt100Ctrl_t Pt100Ctrl;

/* 获取设备数量 */
static uint8_t AOMGetDevNum(int type)
{
    uint8_t num = 0;

    switch (type) {
    case IET_ECU:
    case IET_DI:
    case IET_DO:
    case IET_AI:
    case IET_AO:
    case IET_PI:
    case IET_SOE:
    case IET_AC:
        goto err_retrun;
    case IET_PT100:
        num = PT100_PT100M_CHANNEL;
        break;
    case IET_IEPE:
        goto err_retrun;
    default:
        prt_erro("Invalid type %d for %s\n", type, __func__);
        return 0;
    }
    prt_info("%s get %d device\n", __func__, num);

    return num;

err_retrun:
    prt_erro("%s get no device\n", __func__);

    return 0;
};

/* 打开设备 */
int PT100MOpen(int moduleType)
{
    struct Pt100Ctrl_t *pctrl = &Pt100Ctrl;
    struct Pt100Dev_t *pdev = &pctrl->dev[0];
    int ret = 0;
    uint8_t i = 0;
    int8_t j = 0;

    pctrl->num = AOMGetDevNum(moduleType);
    pctrl->max_num = PT100_MAX_CHANNEL;
    pctrl->type = (uint8_t)moduleType;
    /* 检查参数 */
    if (pctrl->num > pctrl->max_num) {
        prt_erro("Get PT100 number %d, max is %d\n", pctrl->num, pctrl->max_num);
        return -EFAULT;
    }
    /* 生成路径 */
    snprintf(pctrl->name, sizeof(pctrl->name), "%s", PT100_DRV_NAME);
    for (i = 0; i < pctrl->num; i++) {
        pdev = &pctrl->dev[i];
        pdev->parent = pctrl;
        snprintf(pdev->name, sizeof(pdev->name), "%s%d", pctrl->name, i);
        pdev->index = i;
        pdev->fd = -ENODEV;
        ret = snprintf(pdev->path, PATH_MAX, "/dev/%s", pdev->name);
        if (ret < 0 || ret >= PATH_MAX) {
            prt_erro("Generate %s path failed\n", pdev->name);
            return -ENAMETOOLONG;
        }
        /* 打开设备 */
        pdev->fd = open(pdev->path, O_RDWR);
        if (pdev->fd < 0) {
            ret = errno;
            prt_erro("Open %s device failed, %s\n", pdev->path, strerror(ret));
            ret = -ret;
            goto err_close_fd;
        }
        prt_dbug("Open %s device success\n", pdev->path);
    }

    pdev = &pctrl->dev[0];
    /* 获取驱动版本号 */
    ret = ioctl(pdev->fd, IOCTL_PT100_GET_DRV_VERSION, &pctrl->drvVer);
    if (ret < 0) {
        prt_erro("Get PT100 driver version 0x%08x failed\n", pctrl->drvVer);
        goto err_close_fd;
    }
    prt_dbug("Get PT100 driver version 0x%08x\n", pctrl->drvVer);
    /* 获取 FPGA 版本号 */
    ret = ioctl(pdev->fd, IOCTL_PT100_GET_FPGA_VERSION, &pctrl->fpgaVer);
    if (ret < 0) {
        prt_erro("Get PT100 FPGA version 0x%08x failed\n", pctrl->fpgaVer);
        goto err_close_fd;
    }
    prt_dbug("Get PT100 FPGA version 0x%08x\n", pctrl->fpgaVer);
    pctrl->libVer = LIB_VERSION(PT_VER_MAJOR, PT_VER_MINOR, PT_VER_PATCH);
    prt_dbug("Get PT100 library version 0x%08x\n", pctrl->libVer);

    return 0;

err_close_fd:
    for (j = i - 1; j >= 0; j--) {
        pdev = &pctrl->dev[j];
        close(pdev->fd);
        pdev->fd = -ENODEV;
    }

    return ret;
}

/* 初始化设备 */
int PT100MInit()
{
    struct Pt100Ctrl_t *pctrl = &Pt100Ctrl;
    struct Pt100Dev_t *pdev = &pctrl->dev[0];
    int ret = 0;
    uint8_t i = 0;

    pctrl->mode = PT100_DEV_MOD_NORMAL;
    pctrl->sampRate = PT100_DEF_SAMP_RATE;
    pctrl->slidWin = PT100_DEF_SLIDE_WIN;

    /* 检查参数 */
    if (pdev->fd == 0 || 
        pctrl->mode > PT100_DEV_MOD_DMA || 
        pctrl->sampRate > PT100_MAX_SAMP_RATE || 
        pctrl->slidWin > PT100_MAX_SLIDE_WIN) {
        prt_erro("Invalid parameters for %s\n", __func__);
        return -EFAULT;
    }

    /* 配置 PT100 模式 */
    ret = ioctl(pdev->fd, IOCTL_PT100_SET_MODE, &pctrl->mode);
    if (ret < 0) {
        prt_erro("Set PT100 mode %d failed\n", pctrl->mode);
        goto err_return;
    }
    prt_dbug("Set PT100 mode %d success\n", pctrl->mode);
    /* 配置 PT100 采样频率 */
    ret = ioctl(pdev->fd, IOCTL_PT100_SET_SAMP_RATE, &pctrl->sampRate);
    if (ret < 0) {
        prt_erro("Set PT100 sample rate %dHz failed\n", pctrl->sampRate);
        goto err_return;
    }
    prt_dbug("Set PT100 sample rate %dHz success\n", pctrl->sampRate);
    /* 配置 PT100 滑动平均窗口 */
    ret = ioctl(pdev->fd, IOCTL_PT100_SET_SLID_WIN, &pctrl->slidWin);
    if (ret < 0) {
        prt_erro("Set PT100 slide window %d failed\n", pctrl->slidWin);
        goto err_return;
    }
    prt_dbug("Set PT100 slide window %d success\n", pctrl->slidWin);

    /* 配置 PT100 量程 */
    for (i = 0; i < pctrl->num; i++) {
        pdev = &pctrl->dev[i];
        /* 检查参数 */
        if (pdev->fd == 0 || 
            pdev->range > PT100_DEV_RANGE_5V) {
            prt_erro("Invalid parameters for PT100 %s\n", __func__);
            ret = -EFAULT;
            goto err_return;
        }
        pdev->range = PT100_DEV_RANGE_10V;

        /* 配置 PT100 量程 */
        ret = ioctl(pdev->fd, IOCTL_PT100_SET_RANGE, &pdev->range);
        if (ret < 0) {
            prt_erro("Set PT100 %2d range %d failed\n", pdev->index, pdev->range);
            goto err_return;
        }
        prt_dbug("Set PT100 %2d range %d success\n", pdev->index, pdev->range);
    }
    pdev = &pctrl->dev[0];
    /* 开始 PT100 采集 */
    ret = ioctl(pdev->fd, IOCTL_PT100_START);
    if (ret < 0) {
        prt_erro("Start PT100 failed\n");
        return -EFAULT;
    }
    prt_dbug("Start PT100 success\n");

    return 0;

err_return:

    return ret;
}

/* PT100温度-电阻关系多项式系数 (根据IEC 60751标准) */
/* 温度范围：-200°C 至 0°C: R(t) = R0[1 + At + Bt² + C(t-100)t³] */
/* 温度范围：0°C 至 850°C: R(t) = R0(1 + At + Bt²) */

#define PT100_R0 100.0  /* PT100在0°C时的电阻值 */

/* 系数定义 (IEC 60751标准) */
#define PT100_A 3.9083e-3
#define PT100_B -5.775e-7
#define PT100_C -4.183e-12

/**
 * @brief 使用牛顿迭代法计算PT100电阻对应的温度
 * @param resistance 测得的电阻值(Ω)
 * @param initial_guess 初始温度猜测值(°C)
 * @param max_iterations 最大迭代次数
 * @param tolerance 收敛容差
 * @return 计算得到的温度值(°C)，如果计算失败返回NAN
 */
static double pt100_resistance_to_temp(double resistance, double initial_guess, 
                               int max_iterations, double tolerance) {
    double t = initial_guess;   /* 初始温度猜测 */
    int iteration = 0;
    
    /* 检查电阻值是否在合理范围内 */
    if (resistance < 18.52 || resistance > 390.48) { /* -200°C to 850°C对应的电阻范围 */
        return NAN;
    }
    
    while (iteration < max_iterations) {
        double rt, drdt;
        
        /* 根据温度范围选择不同的多项式 */
        if (t < 0) {
            /* -200°C 至 0°C 范围 */
            rt = PT100_R0 * (1 + PT100_A * t + PT100_B * t * t + PT100_C * (t - 100) * t * t * t);
            drdt = PT100_R0 * (PT100_A + 2 * PT100_B * t + PT100_C * (4 * t * t * t - 300 * t * t));
        } else {
            /* 0°C 至 850°C 范围 */
            rt = PT100_R0 * (1 + PT100_A * t + PT100_B * t * t);
            drdt = PT100_R0 * (PT100_A + 2 * PT100_B * t);
        }
        
        /* 计算函数值和导数 */
        double f = rt - resistance;
        double f_prime = drdt;
        
        /* 检查导数是否接近零，避免除零错误 */
        if (fabs(f_prime) < 1e-15) { /* 使用更小的阈值 */
            return NAN;  /* 返回非数值表示计算失败 */
        }
        
        /* 牛顿迭代公式: t_new = t_old - f(t)/f'(t) */
        double t_new = t - f / f_prime;
        
        /* 检查是否收敛 */
        if (fabs(t_new - t) < tolerance) {
            /* 验证结果是否在合理范围内 */
            if (t_new >= -200 && t_new <= 850) {
                return t_new;
            } else {
                return NAN;
            }
        }
        
        /* 防止迭代发散 */
        if (t_new < -250 || t_new > 900) {
            return NAN;
        }
        
        t = t_new;
        iteration++;
    }
    
    /* 如果达到最大迭代次数仍未收敛 */
    return NAN;
}

/**
 * @brief PT100电阻-温度查表（间隔10°C，用于获取初始温度猜测）
 */
static const struct {
    double resistance; /* 电阻值(Ω) */
    double temperature; /* 温度值(°C) */
} pt100_lookup_table[] = {
    /* -200°C to -100°C (间隔10°C) */
    {18.52, -200}, {22.83, -190}, {27.10, -180}, {31.34, -170}, {35.54, -160},
    {39.72, -150}, {43.88, -140}, {48.00, -130}, {52.11, -120}, {56.19, -110},
    {60.26, -100},
    
    /* -100°C to 0°C (间隔10°C) */
    {60.26, -100}, {64.30, -90}, {68.33, -80}, {72.33, -70}, {76.33, -60},
    {80.31, -50}, {84.27, -40}, {88.22, -30}, {92.16, -20}, {96.09, -10},
    {100.00, 0},
    
    /* 0°C to 850°C (间隔10°C) */
    {100.00, 0}, {103.90, 10}, {107.79, 20}, {111.67, 30}, {115.54, 40},
    {119.40, 50}, {123.24, 60}, {127.07, 70}, {130.89, 80}, {134.70, 90},
    {138.50, 100}, {142.29, 110}, {146.07, 120}, {149.83, 130}, {153.58, 140},
    {157.33, 150}, {161.05, 160}, {164.77, 170}, {168.48, 180}, {172.17, 190},
    {175.86, 200}, {179.53, 210}, {183.19, 220}, {186.84, 230}, {190.47, 240},
    {194.10, 250}, {197.71, 260}, {201.31, 270}, {204.90, 280}, {208.48, 290},
    {212.05, 300}, {215.61, 310}, {219.15, 320}, {222.68, 330}, {226.21, 340},
    {229.72, 350}, {233.21, 360}, {236.70, 370}, {240.18, 380}, {243.64, 390},
    {247.09, 400}, {250.53, 410}, {253.96, 420}, {257.38, 430}, {260.78, 440},
    {264.18, 450}, {267.56, 460}, {270.93, 470}, {274.29, 480}, {277.64, 490},
    {280.98, 500}, {284.30, 510}, {287.62, 520}, {290.92, 530}, {294.21, 540},
    {297.49, 550}, {300.76, 560}, {304.02, 570}, {307.26, 580}, {310.50, 590},
    {313.72, 600}, {316.93, 610}, {320.13, 620}, {323.32, 630}, {326.50, 640},
    {329.67, 650}, {332.82, 660}, {335.97, 670}, {339.10, 680}, {342.22, 690},
    {345.33, 700}, {348.43, 710}, {351.52, 720}, {354.59, 730}, {357.66, 740},
    {360.71, 750}, {363.75, 760}, {366.78, 770}, {369.80, 780}, {372.81, 790},
    {375.81, 800}, {378.79, 810}, {381.77, 820}, {384.73, 830}, {387.68, 840},
    {390.48, 850}  /* 注意：850°C时电阻为390.48Ω */
};

#define PT100_TABLE_SIZE (int)(sizeof(pt100_lookup_table) / sizeof(pt100_lookup_table[0]))

/**
 * @brief 通过查表法获取PT100电阻对应的初始温度猜测
 * @param resistance 测得的电阻值(Ω)
 * @return 查表得到的初始温度猜测值(°C)，如果失败返回0°C
 */
static double pt100_get_initial_temp_from_table(double resistance) {
    /* 检查边界情况 */
    if (resistance < pt100_lookup_table[0].resistance) {
        return pt100_lookup_table[0].temperature; /* 低于最小值，返回最低温度 */
    }
    if (resistance > pt100_lookup_table[PT100_TABLE_SIZE - 1].resistance) {
        return pt100_lookup_table[PT100_TABLE_SIZE - 1].temperature; /* 高于最大值，返回最高温度 */
    }
    
    /* 二分查找最接近的电阻值 */
    int left = 0;
    int right = PT100_TABLE_SIZE - 1;
    
    while (left <= right) {
        int mid = left + (right - left) / 2;
        
        if (fabs(pt100_lookup_table[mid].resistance - resistance) < 0.1) {
            /* 找到非常接近的值 */
            return pt100_lookup_table[mid].temperature;
        }
        
        if (pt100_lookup_table[mid].resistance < resistance) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    
    /* 线性插值获取更精确的初始温度 */
    if (right < 0) right = 0;
    if (left >= PT100_TABLE_SIZE) left = PT100_TABLE_SIZE - 1;
    
    int idx1 = (left < right) ? left : right;
    int idx2 = (left < right) ? right : left;
    
    if (idx1 == idx2) {
        return pt100_lookup_table[idx1].temperature;
    }
    
    double r1 = pt100_lookup_table[idx1].resistance;
    double r2 = pt100_lookup_table[idx2].resistance;
    double t1 = pt100_lookup_table[idx1].temperature;
    double t2 = pt100_lookup_table[idx2].temperature;
    
    /* 线性插值公式 */
    return t1 + (resistance - r1) * (t2 - t1) / (r2 - r1);
}

/**
 * @brief 使用查表法获取初始温度的改进版温度计算函数
 * @param resistance 测得的电阻值(Ω)
 * @param max_iterations 最大迭代次数
 * @param tolerance 收敛容差
 * @return 计算得到的温度值(°C)
 */
static double pt100_resistance_to_temp_with_table(double resistance, 
                                         int max_iterations, double tolerance) {
    double initial_guess = pt100_get_initial_temp_from_table(resistance);
    return pt100_resistance_to_temp(resistance, initial_guess, max_iterations, tolerance);
}

/**
 * @brief 简化接口函数，使用查表法获取初始温度
 * @param resistance 测得的电阻值(Ω)
 * @return 计算得到的温度值(°C)
 */
static double pt100_calculate_temp_improved(double resistance) {
    /* 使用查表法获取初始温度，最大迭代50次，容差0.001°C */
    return pt100_resistance_to_temp_with_table(resistance, 50, 0.001);
}

int PT100MReadReal(int channel, double *data)
{
    struct Pt100Ctrl_t *pctrl = &Pt100Ctrl;
    struct Pt100Dev_t *pdev = &pctrl->dev[0];
    int ret = 0;

    /* 检查参数 */
    if (!data || 
        channel < 0 || channel >= pctrl->num) {
        prt_erro("Invalid parameters for %s\n", __func__);
        return -EFAULT;
    }
    pdev = &pctrl->dev[channel];
    /* 检查参数 */
    if (pdev->fd == 0) {
        prt_erro("Invalid %s->fd for %s\n", pdev->name, __func__);
        return -EFAULT;
    }
    /* 获取 PT100 数值 */
    ret = ioctl(pdev->fd, IOCTL_PT100_GET_VAL, &pdev->rawVal);
    if (ret < 0) {
        prt_erro("Get PT100 %2d voltage failed\n", pdev->index);
        return -EFAULT;
    }
    pdev->voltVal = 1.0 * pdev->rawVal / PT100_UV_TO_V;
    prt_info("Get PT100 %2d voltage %.6lfV\n", pdev->index, pdev->voltVal);
    pdev->ohmVal = pdev->voltVal * PT100_V_2_OHM;
    prt_info("Get PT100 %2d resistor %.6lfOhm\n", pdev->index, pdev->ohmVal);
    pdev->tempVal = pt100_calculate_temp_improved(pdev->ohmVal);
    prt_info("Get PT100 %2d temperature %.6lfC\n", pdev->index, pdev->tempVal);
    *data = pdev->tempVal;

    return 0;
}

int PT100MClose()
{
    struct Pt100Ctrl_t *pctrl = &Pt100Ctrl;
    struct Pt100Dev_t *pdev = &pctrl->dev[0];
    int ret = 0;
    uint8_t i = 0;

    for (i = 0; i < pctrl->num; i++) {
        pdev = &pctrl->dev[i];
        /* 检查参数 */
        if (pdev->fd == 0) {
            prt_erro("Invalid %s->fd for %s\n", pdev->name, __func__);
            return -EFAULT;
        }
        /* 停止 PT100 采集 */
        ret = ioctl(pdev->fd, IOCTL_PT100_STOP);
        if (ret < 0) {
            prt_erro("Stop PT100 failed\n");
            return -EFAULT;
        }
        prt_dbug("Stop PT100 success\n");
        /* 关闭设备 */
        ret = close(pdev->fd);
        if (ret != 0) {
            prt_erro("Close %s failed\n", pdev->path);
            return -EFAULT;
        }
        pdev->fd = 0;
        prt_dbug("Close %s success\n", pdev->path);
    }

    return 0;
}

/* 获取驱动版本号 */
int PT100MGetDrvVer()
{
    struct Pt100Ctrl_t *pctrl = &Pt100Ctrl;

    prt_dbug("%s %d.%d.%d\n", __func__, ((pctrl->drvVer >> 24) & 0xFF), 
             ((pctrl->drvVer >> 16) & 0xFF), (pctrl->drvVer & 0xFFFF));

    return (int)(pctrl->drvVer >> 16);
}

/* 获取 FPGA 版本号 */
int PT100MGetFpgaVer()
{
    struct Pt100Ctrl_t *pctrl = &Pt100Ctrl;

    prt_dbug("%s %d.%d\n", __func__, ((pctrl->fpgaVer >> 8) & 0xFF), 
             (pctrl->fpgaVer & 0xFF));

    return (int)(pctrl->fpgaVer);
}

/* 获取动态库版本号 */
int PT100MGetLibVer()
{
    struct Pt100Ctrl_t *pctrl = &Pt100Ctrl;

    prt_dbug("%s %d.%d.%d\n", __func__, ((pctrl->libVer >> 24) & 0xFF), 
             ((pctrl->libVer >> 16) & 0xFF), (pctrl->libVer & 0xFFFF));

    return (int)(pctrl->libVer >> 16);
}
